/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    spi.c
  * @brief   This file provides code for the configuration
  *          of the SPI instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "spi.h"

/* USER CODE BEGIN 0 */
#include "error.h"
#include "loop_function.h"
#include "crc.h"
/* USER CODE END 0 */

SPI_HandleTypeDef hspi3;
DMA_HandleTypeDef hdma_spi3_rx;
DMA_HandleTypeDef hdma_spi3_tx;

/* SPI3 init function */
void MX_SPI3_Init(void)
{

  /* USER CODE BEGIN SPI3_Init 0 */

  /* USER CODE END SPI3_Init 0 */

  /* USER CODE BEGIN SPI3_Init 1 */

  /* USER CODE END SPI3_Init 1 */
  hspi3.Instance = SPI3;
  hspi3.Init.Mode = SPI_MODE_SLAVE;
  hspi3.Init.Direction = SPI_DIRECTION_2LINES;
  hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi3.Init.NSS = SPI_NSS_HARD_INPUT;
  hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_ENABLE;
  hspi3.Init.CRCPolynomial = 7;
  if (HAL_SPI_Init(&hspi3) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI3_Init 2 */

  /* USER CODE END SPI3_Init 2 */

}

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(spiHandle->Instance==SPI3)
  {
  /* USER CODE BEGIN SPI3_MspInit 0 */

  /* USER CODE END SPI3_MspInit 0 */
    /* SPI3 clock enable */
    __HAL_RCC_SPI3_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    /**SPI3 GPIO Configuration
    PA15     ------> SPI3_NSS
    PC10     ------> SPI3_SCK
    PC11     ------> SPI3_MISO
    PC12     ------> SPI3_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* SPI3 DMA Init */
    /* SPI3_RX Init */
    hdma_spi3_rx.Instance = DMA1_Stream0;
    hdma_spi3_rx.Init.Channel = DMA_CHANNEL_0;
    hdma_spi3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi3_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi3_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi3_rx.Init.Mode = DMA_NORMAL;
    hdma_spi3_rx.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_spi3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_spi3_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(spiHandle,hdmarx,hdma_spi3_rx);

    /* SPI3_TX Init */
    hdma_spi3_tx.Instance = DMA1_Stream5;
    hdma_spi3_tx.Init.Channel = DMA_CHANNEL_0;
    hdma_spi3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi3_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi3_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi3_tx.Init.Mode = DMA_NORMAL;
    hdma_spi3_tx.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_spi3_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_spi3_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(spiHandle,hdmatx,hdma_spi3_tx);

  /* USER CODE BEGIN SPI3_MspInit 1 */

  /* USER CODE END SPI3_MspInit 1 */
  }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{

  if(spiHandle->Instance==SPI3)
  {
  /* USER CODE BEGIN SPI3_MspDeInit 0 */

  /* USER CODE END SPI3_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI3_CLK_DISABLE();

    /**SPI3 GPIO Configuration
    PA15     ------> SPI3_NSS
    PC10     ------> SPI3_SCK
    PC11     ------> SPI3_MISO
    PC12     ------> SPI3_MOSI
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_15);

    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12);

    /* SPI3 DMA DeInit */
    HAL_DMA_DeInit(spiHandle->hdmarx);
    HAL_DMA_DeInit(spiHandle->hdmatx);
  /* USER CODE BEGIN SPI3_MspDeInit 1 */

  /* USER CODE END SPI3_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) {
	if(hspi->Instance != SPI3)
	{
		return;
	}
  uint32_t err = hspi->ErrorCode;
  if (err & HAL_SPI_ERROR_MODF) {
  	error_assert(ERR_HAL_SPI_TransmitReceive_IT);
  }
  if (err & HAL_SPI_ERROR_OVR) {
  	error_assert(ERR_HAL_SPI_TransmitReceive_IT);
  }
  if (err & HAL_SPI_ERROR_ABORT) {
  	error_assert(ERR_HAL_SPI_TransmitReceive_IT);
  }
  if (err & HAL_SPI_ERROR_CRC) {
  	error_assert(ERR_HAL_SPI_TransmitReceive_IT);
  	__HAL_SPI_CLEAR_CRCERRFLAG(hspi);
  }
  if (err & HAL_SPI_ERROR_DMA) {
  	error_assert(ERR_HAL_SPI_TransmitReceive_IT);
  }
  if (err & HAL_SPI_ERROR_FLAG) {
    uint32_t sr = hspi->Instance->SR;
    if (sr & SPI_FLAG_TXE) {
    	error_assert(ERR_HAL_SPI_TransmitReceive_IT);
    }
    if (sr & SPI_FLAG_BSY) {
    	error_assert(ERR_HAL_SPI_TransmitReceive_IT);
    }
    if (sr & SPI_FLAG_CRCERR) {
    	error_assert(ERR_HAL_SPI_TransmitReceive_IT);
    }
    if (sr & SPI_FLAG_OVR) {
    	error_assert(ERR_HAL_SPI_TransmitReceive_IT);
    }
  }
  uint32_t error_flags = __HAL_SPI_GET_FLAG(&hspi3, SPI_FLAG_OVR |
                                                SPI_FLAG_CRCERR |
                                                SPI_FLAG_MODF |
                                                SPI_FLAG_BSY);

  if (error_flags) {
      __HAL_SPI_CLEAR_OVRFLAG(&hspi3);
      __HAL_SPI_CLEAR_CRCERRFLAG(&hspi3);
      __HAL_SPI_CLEAR_MODFFLAG(&hspi3);
  }

  HAL_SPI_DMAStop(&hspi3);
  HAL_SPI_DeInit(&hspi3);
  __HAL_RCC_SPI3_FORCE_RESET();
  __HAL_RCC_SPI3_RELEASE_RESET();
  HAL_SPI_Init(&hspi3);
  SPI_RESET_CRC(&hspi3);
  HAL_SPI_TransmitReceive_DMA(&hspi3, _get_spitx_buf(), _get_spirx_queue_buf(), _get_spirx_queue_buf_size());
}

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
	if(hspi->Instance != SPI3)
	{
		return;
	}
	_get_spitx_msg();

  uint32_t error_state = HAL_SPI_GetError(hspi);
  if((error_state & HAL_SPI_ERROR_CRC) == HAL_SPI_ERROR_CRC)
  {
      HAL_SPI_DMAStop(hspi);
      HAL_SPI_DeInit(hspi);
  	  __HAL_RCC_SPI3_FORCE_RESET();
  	  __HAL_RCC_SPI3_RELEASE_RESET();
  	  HAL_SPI_Init(&hspi3);
  	  _reset_spirx_msglen();
  }
  else
  {
  	if(_push_spirx_queue())
  	{
  		error_assert(ERR_FULLBUF_SPIRX);
  	}
  }

  SPI_RESET_CRC(hspi);
  if(HAL_SPI_TransmitReceive_DMA(hspi, _get_spitx_buf(), _get_spirx_queue_buf(), _get_spirx_queue_buf_size()) != HAL_OK)
	{
		error_assert(ERR_HAL_SPI_TransmitReceive_IT);
	}
}
/* USER CODE END 1 */
